package com.piece.core.web.config;

import com.piece.core.framework.enums.WebFilterOrder;
import com.piece.core.framework.util.cache.Cache;
import com.piece.core.framework.util.lock.DistributedLock;
import com.piece.core.web.authority.AuthorityFactory;
import com.piece.core.web.authority.AuthorityService;
import com.piece.core.web.filter.CacheRequestBodyFilter;
import com.piece.core.web.filter.ContextFilter;
import com.piece.core.web.filter.FilterHook;
import com.piece.core.web.filter.FilterHookManager;
import com.piece.core.web.interceptor.CacheServiceInterceptor;
import com.piece.core.web.interceptor.InterceptorHook;
import com.piece.core.web.interceptor.InterceptorHookManager;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Map;

@Order(Integer.MIN_VALUE)
@EnableAsync(proxyTargetClass = true)
public class WebAutoConfiguration {

    @Autowired(required = false)
    private Map<String, FilterHook> filterHookMap;

    @Bean
    public AuthorityFactory tokenFactory(Map<String, AuthorityService> authorityServiceMap) {
        return new AuthorityFactory(authorityServiceMap);
    }

    @Bean
    @ConditionalOnClass({HttpServletRequest.class})
    public FilterHookManager filterHookManager() {
        return new FilterHookManager(filterHookMap);
    }

    @Bean
    @ConditionalOnClass({HttpServletRequest.class})
    public InterceptorHookManager interceptorHookManager(Map<String, InterceptorHook> interceptorHookMap) {
        return new InterceptorHookManager(interceptorHookMap);
    }

    @Bean
    @ConditionalOnBean({DistributedLock.class, Cache.class })
    public DefaultPointcutAdvisor defaultPointcutAdvisor(DistributedLock locker, Cache cache) {
        CacheServiceInterceptor interceptor = new CacheServiceInterceptor(locker, cache);
        JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
        pointcut.setPattern("com.piece..service.*(..)");
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        return advisor;
    }

//    @Bean
//    @ConditionalOnClass({HttpServletRequest.class})
    public CorsFilter corsFilter() {
        // 创建 CorsConfiguration 对象
        CorsConfiguration config = new CorsConfiguration();
        // 允许凭证
        config.setAllowCredentials(true);
        // 允许任何来源
        config.setAllowedOriginPatterns(Collections.singletonList("*"));
        // 允许任何请求头
        config.addAllowedHeader(CorsConfiguration.ALL);
        // 允许任何方法
        config.addAllowedMethod(CorsConfiguration.ALL);
        // 创建 UrlBasedCorsConfigurationSource 对象
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config); // 对接口配置跨域设置
        return new CorsFilter(source);
    }

    @Bean
    @ConditionalOnClass({HttpServletRequest.class})
    public FilterRegistrationBean<CacheRequestBodyFilter> cacheRequestBodyFilter() {
        return createFilterBean(new CacheRequestBodyFilter(), WebFilterOrder.CACHE_REQUEST_BODY_FILTER);
    }

    @Bean
    @ConditionalOnClass({HttpServletRequest.class})
    public FilterRegistrationBean<ContextFilter> contextFilter(FilterHookManager filterHookManager) {
        return createFilterBean(new ContextFilter(filterHookManager), WebFilterOrder.CONTEXT_FILTER);
    }

    private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
        FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
        bean.setOrder(order);
        return bean;
    }
}
